/**
 * Copyright (c) Martijn Grootens (m.e.grootens@student.utwente.nl), 
 * University of Twente.
 * Created january 2013.
 *
 * This file is part of dbcleaner.
 * 
 * dbcleaner is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * dbcleaner is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with dbcleaner.  If not, see <http://www.gnu.org/licenses/>.
 */

package dbcleaner;

import java.io.*;
import java.util.*;
import dbcleaner.core.dbentries.*;
import dbcleaner.core.parse.*;
import dbcleaner.core.fix.*;
import dbcleaner.core.tags.*;
import dbcleaner.core.bibfields.*;

import java.util.Date;
import java.text.DateFormat;
import java.text.SimpleDateFormat;



/**
 * Clean up database file
 */
public class MatchPageNumbers {

	// The paths to the sense and non_sense tags.
    public static final String tags_sense_pwd = "dbcleaner/tags/sense.txt";
    public static final String tags_nonsense_pwd = "dbcleaner/tags/non_sense.txt";
	
	public static final String in_db_wp_pwd = "./dbcleaner/dbase/group-13900.bib";
   
    /**
     * Main. One argument; input BibTeX file with missing pagenumbers.
     */
    public static void main(String[] args) {
        
        // The date will be appended to the output file.
        DateFormat date_format = new SimpleDateFormat("MM.dd_HH.mm.ss");
        Date today = new Date();
        String append = date_format.format(today);
		
		
		// Empty TagLists and DataBase.
        TagList tags_sense = new TagList();
        TagList tags_nonsense = new TagList();
		
        
		
		
		DataBase db_wp = new DataBase();
        DataBase db = new DataBase();
        
        try {

            
            // = = = = = = = = = = = = = = = = = = = = = = = = \\
            // Read the lists of tags
            
            System.out.println("Reading tags...");
            
            tags_sense = TagListFactory.read_TagList(new File(tags_sense_pwd),"sense");
            tags_nonsense =  TagListFactory.read_TagList(new File(tags_nonsense_pwd),"non_sense");
            
            
            
            // = = = = = = = = = = = = = = = = = = = = = = = = \\
            // Fetch path to input file
            String in_db_pwd  = args[0];
            
            System.out.println("Reading database...");
            
            // Create a scanner for the input file and start reading.
            File in_db_f  = new File(in_db_pwd);  // input file
            Scanner in_db = new Scanner(in_db_f);
            
            // Create the DataBase.
            db = DataBaseFactory.read_input_file(in_db);
            
            
			
			
			
			
			
			// = = = = = = = = = = = = = = = = = = = = = = = = \\
            // Read source for pagenumbers
            System.out.println("Reading pagenumber source...");
			
			// Create a scanner for the input file and start reading.
            File in_db_wp_f  = new File(in_db_wp_pwd);  // input file
            Scanner in_db_wp = new Scanner(in_db_wp_f);
            
            // Create the DataBase.
            db_wp = DataBaseFactory.read_input_file(in_db_wp);
			
			
			
			
			
			
			
			
			// = = = = = = = = = = = = = = = = = = = = = = = = \\
            // Now go and fix the Tags.
            System.out.println("Fixing database tags...");
            System.out.println("\tDeleting and replacing tags...");
            TagFixer.fix_tags(db,tags_sense,tags_nonsense);
            
            
            
            
            
            // = = = = = = = = = = = = = = = = = = = = = = = = \\
            // Tag incomplete Entries.
            System.out.println("\tTagging incompletes...");
            int num_incompletes = CompletenessChecker.tag_incompletes(db,"_INCOMPLETE");
            System.out.println("\t\tNum tagged: " + num_incompletes);
            
            // Tag incomplete Entries that DO have a doi.
            System.out.println("\tTagging incompletes with doi...");
            int num_incompletes_w_doi = CompletenessChecker.tag_incompletes_with_doi(db,"_INCOMPLETE_W_DOI");
            System.out.println("\t\tNum tagged: " + num_incompletes_w_doi);
            
            
            
            
            
            
            // = = = = = = = = = = = = = = = = = = = = = = = = \\
            System.out.println("\tTagging slashes in title...");
            // Tag all with backslash in title
            int num_slashes_title = 0;
            for (Entry e : db.get_entries()) {
                if (e.get_field_contents("title").indexOf("\\")>-1){
                    e.add_tag(new Tag("_BACKSLASH_IN_TITLE"));
                    ++num_slashes_title;
                }
            }
            System.out.println("\t\tNum tagged: " + num_slashes_title);
			
			
			
			
			
			
			
			// = = = = = = = = = = = = = = = = = = = = = = = = \\
            // Now go and recreate labels
            System.out.println("Creating new TeX labels...");
            LabelFixer.fix_labels(db);
			
			
			
			
			
			
			// = = = = = = = = = = = = = = = = = = = = = = = = \\
			// Page number fixing
			System.out.println("Finding pagenumbers");
			// dump accepted page numbers
			dump_old_pagenums(db);
			fetch_pagenumbers(db,db_wp);
			
			
			
			
			
			
			
			
			
			// = = = = = = = = = = = = = = = = = = = = = = = = \\
			// Double titles
			tag_double_titles(db);
			
			
			
			
			
			
			
			
            
            
            // = = = = = = = = = = = = = = = = = = = = = = = = \\
            // Write to file, 1500 per file
            System.out.println("Writing database...");
            write_dbase(db, in_db_pwd, append, 1500);
           
            
            
            
			
			
			
			
			
			
			// = = = = = = = = = = = = = = = = = = = = = = = = \\
            // Check if double CiteULike ID's occur
            
            System.out.println("Checking for double CiteULike ID's...");
            boolean has_double_id = has_double_cul_id(db);
            
            if (has_double_id)
                System.out.println("\tWARNING: double ID's occured!");
            else
                System.out.println("\tNo double ID's found.");
			
			// = = = = = = = = = = = = = = = = = = = = = = = = \\
            // Write all labels to disk, for easy checking
            
            System.out.println("Writing label log file...");
            write_label_log(db,"dbcleaner/log/labels_"+append+".txt");
            
            
            
        }
        catch (Exception e) {
            System.out.println(e);
            System.exit(1);
        }
        
        System.out.println("Done.");
        System.exit(0);
    }
    
    
    
    
    
    /**
     * Create the BufferedWriter for writing the output files;
     * only to ensure correct naming before file extension.
     */
    private static BufferedWriter out_file_writer (String in_db_pwd, String append, int part_num) {
        
        String out_db_pwd;
        
        int index_dot = in_db_pwd.lastIndexOf(".");
        if (index_dot>0)
            out_db_pwd = in_db_pwd.substring(0,index_dot) + "_cleaned_" + append + "_part_" + part_num + in_db_pwd.substring(index_dot);
        else
            out_db_pwd = in_db_pwd + "_cleaned_" + append + "_part_" + part_num + ".bib";
        
        try {
            return new BufferedWriter(new FileWriter(new File(out_db_pwd)));
        }
        catch (Exception e) {
            System.out.println(e);
            System.exit(1);
        }
        return null;
        
    }
    

    /**
     * Write DataBase to disk.
     */
    private static void write_dbase (DataBase db, String base_name, String append, int num_pf) {
        
        try {
            
            // no more than num_pf entries per file
            int entries_printed=0;
            int num_files=1;
        
            BufferedWriter out = out_file_writer(base_name, append, num_files);
            
            for (Entry e : db.get_entries()) {
                
                out.write(e.toString());
                
                ++entries_printed;
                
                if (entries_printed>=1500) {
                    entries_printed=0;
                    ++num_files;
                    out.close();
                    
                    out = out_file_writer(base_name, append, num_files);
                }
                
            }
            
            out.close();
            }
            catch (Exception e) {
                System.out.println(e);
                System.exit(1);
            }
    }
    
    
    
    
    /**
     * Check for duplicate CitULike ID's; should not occur.
     */
    private static boolean has_double_cul_id (DataBase db) {
        
        ArrayList<Entry> the_db = db.get_entries();
        boolean has_doubles = false;
        
        int num = the_db.size();
        for (int ii=0; ii<num; ++ii  ) {
            for (int jj=ii+1; jj<num; jj++) {
                if (
                    the_db.get(ii).get_field_contents("citeulike-article-id").equals(the_db.get(jj).get_field_contents("citeulike-article-id"))
                    ) {
                    System.out.println("\t* double CiteULike ID's for id " + the_db.get(ii).get_id() + " && " + the_db.get(jj).get_id());
                    has_doubles = true;
                }
                
            }
        }
        
        return has_doubles;
        
    }
    
    
    
    
    
    
    /**
     * Writing a list of labels to disk
     */
    private static void write_label_log (DataBase db, String to_file) {
        try{
            BufferedWriter l_out =
            new BufferedWriter(new FileWriter(new File(to_file)));
            
            for (Entry e : db.get_entries())
                l_out.write(e.get_label()+"\n");
            
            l_out.close();
        }
        catch (Exception e) {
            System.out.println(e);
            System.exit(1);
        }
    }
	
	
	
	
	/**
	 * Dump old page numbers
	 */
	private static void dump_old_pagenums (DataBase db) {
		List<BibField> bf;
		String fname;
		for (Entry e : db.get_entries()) {
			bf = e.get_extra_fields();
			
			for (BibField b : bf) {
				fname = b.get_field_name();
				if (fname.equals("pages")) {
					b.set_field_name("old_pages");
				}
			}
		}
	}
	
	/**
	 * Fetch page numbers, otherwise mark as unmatched
	 * TERRIBLY INEFFICIENT!! SLOW AND DIRTY!!
	 */
	private static void fetch_pagenumbers (DataBase db, DataBase db_wp) {
		
		String mytitle, comptitle, pages, pages_tmp, myauthor, compauthor;
		boolean matched;
		int num_matches;
		int num_mmatch=0;
		int num_unmatch=0;
		int num_match=0;
		Entry last_match;
		
		for (Entry e : db.get_entries()) {
			
			mytitle = e.get_field_contents("title");
			myauthor = e.get_field_contents("author");
			
			
			if (mytitle=="EMPTY") {
				System.out.println("hacky escape :: empty title");
				System.exit(1);
			}
			
			num_matches = 0;
			matched = false;
			last_match = e; //itself
			pages = "EMPTY";
			
			for (Entry e_wp : db_wp.get_entries()) {
				
				
				comptitle = e_wp.get_field_contents("title");
				
				if (mytitle.equals(comptitle)) {
					
					compauthor = e_wp.get_field_contents("author");
					
					if (myauthor.equals(compauthor)) {
					
						//System.out.println("matched::"+mytitle+comptitle);
						++num_matches;
						matched = true;
						pages_tmp = e_wp.get_field_contents("pages");
						if (!pages_tmp.equals("EMPTY")) {
							pages = pages_tmp;
						}
					}
					
				}
				
			}
			
			if (matched) {
				
				if (!pages.equals("EMPTY")) {
					++num_match;
					e.add_BibField(new BibField("pages",pages));
					e.add_tag(new Tag("_MATCHED"));
				}
				
				if (num_matches>1) {
					++num_mmatch;
					e.add_tag(new Tag("_MULTIMATCH"));
				}
				
			} else {
				++num_unmatch;
				e.add_tag(new Tag("_UNMATCHED"));
			}
				
			
		}
		
		System.out.println("\tnumber of matches: " + num_match);
		System.out.println("\tnumber of multimatches: " + num_mmatch);
		System.out.println("\tnumber of unmatched: " + num_unmatch);
		
		
		
	}
	
    /**
     * Search for duplicate titles and tag them
     */
	private static void tag_double_titles (DataBase db) {
		
		String mytitle,comptitle;
		int num_matches=0, num_duplicates=0;
		
		for (Entry e : db.get_entries()) {
			
			mytitle = e.get_field_contents("title");
			
			if (mytitle=="EMPTY") {
				System.out.println("hacky escape :: empty title");
				System.exit(1);
			}
			
			num_matches = 0;
			
			for (Entry e_wp : db.get_entries()) {
				
				
				comptitle = e_wp.get_field_contents("title");
				
				if (mytitle.equals(comptitle)) {
					
					++num_matches;
					
				}
				
			}
			
			if (num_matches>2) {
				e.add_tag(new Tag("_DUPLICATE_TITLE"));
				++num_duplicates;
			}
				
			
		}
		
		System.out.println("num duplicate titled:" + num_duplicates);
		
		
	}
    
    
    
}